package com.kang.service.impl;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.kang.bean.AccessToken;
import com.kang.bean.UserRole;
import com.kang.bean.Users;
import com.kang.commons.Result;
import com.kang.commons.util.*;
import com.kang.commons.util.EmailUtil;
import com.kang.dto.UsersDto;
import com.kang.mapper.UserMapper;
import com.kang.mapper.UserRoleMapper;
import com.kang.service.UserService;
import com.kang.vo.UsersVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * @program: service
 * @description: 用户服务类
 * @author: K.faWu
 * @create: 2022-02-17 16:37
 **/
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, Users> implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserRoleMapper userRoleMapper;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private SMSUtil smsUtil;
    @Autowired
    private QiniuUtil qiniuUtil;

    public static final Integer PHONE_TYPE = 1;
    public static final Integer EMAIL_TYPE = 5;

    @Override
    public Users getById(Long id) {
        return userMapper.getById(id);
    }

    @Override
    public UsersVo login(UsersDto usersDto) {
        int type = usersDto.getType();
        Users users;
        switch (type) {
            case 2:
                users = phoneCode(usersDto);
                break;
            case 3:
                users = vxPass(usersDto);
                break;
            case 4:
                users = qqPass(usersDto);
                break;
            case 5:
                users = emailPass(usersDto);
                break;
            case 6:
                users = emailCode(usersDto);
                break;
            default:
                users = phonePass(usersDto);
        }

        //创建AccessToken
        if (users != null) {
            // 请求参数
            ServletRequestAttributes sre = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = sre.getRequest();
            // 发送请求的IP地址
            String ip = IpUtil.getIpAddr(request);
            /*
             * 登录成功后将登录的手机号和对应的IP地址存到redis中
             */
            redisUtil.setStringObjectByHours(ip, users.getId(), 24);

            QueryWrapper<UserRole> userRoleQueryWrapper = new QueryWrapper<>();
            userRoleQueryWrapper.eq("user_id", users.getId());
            UserRole userRole = userRoleMapper.selectOne(userRoleQueryWrapper);
            if (userRole != null) {
                AccessToken accessToken = new AccessToken(users.getId());
                String json = JSONObject.toJSONString(accessToken);
                String token = EncryptUtil.encrypt(json);
                UsersVo usersVo = new UsersVo();
                BeanUtils.copyProperties(usersVo, users);
                usersVo.setToken(token);
                usersVo.setRoleCode(userRole.getRoleCode());
                return usersVo;
            } else {
                log.info("账号[{}]存在但无权限", users.getId());
                Result.error("登录失败！");
            }
        }
        Result.error("登录失败！");
        return null;
    }

    @Override
    public void register(UsersDto usersDto) {
        int type = usersDto.getType();
        String code = (String) redisUtil.getStringObject(usersDto.getUsername());
        String password = AesEncryptUtil.desEncrypt(usersDto.getPassword());
        usersDto.setPassword(password);
        QueryWrapper<Users> usersQueryWrapper = new QueryWrapper<>();
        if (type == 1) {
            //手机验证码注册
            usersQueryWrapper.eq("phone", usersDto.getUsername());
            usersDto.setPhone(usersDto.getUsername());
        } else if (type == 5) {
            //邮箱验证码注册
            usersQueryWrapper.eq("email", usersDto.getUsername());
            usersDto.setEmail(usersDto.getUsername());
        }
        if (code == null || !code.equals(usersDto.getCode())) {
            Result.error("验证码错误！");
        }
        if (!ObjectUtils.isEmpty(userMapper.selectOne(usersQueryWrapper))) {
            Result.error("请勿重复注册！");
        }
        userMapper.insert(usersDto);

    }

    @Override
    public String getVerificationCode(UsersDto usersDto) {
        int type = usersDto.getType();
        String code = null;
        String time = "5";
        String resutl = null;
        String username = usersDto.getUsername();
        QueryWrapper<Users> wrapper = new QueryWrapper<>();
        if (type == PHONE_TYPE) {
            //手机号获取验证码
            wrapper.eq("phone", username);
            Users users = userMapper.selectOne(wrapper);
            if (ObjectUtils.isEmpty(users)) { //该手机号未注册
                code = smsUtil.sendSms(username, time, SMSUtil.REGISTER);
            } else {
                resutl = "该手机号已注册！";
            }
        } else if (type == EMAIL_TYPE) {
            //获取邮箱验证码
            wrapper.eq("email", username);
            Users users = userMapper.selectOne(wrapper);
            if (ObjectUtils.isEmpty(users)) {
                code = EmailUtil.sendCode(username);
            } else {
                resutl = "该邮箱已注册！";
            }
        }
        if (code != null && code.length() == 6) {
            // 验证码发送成功后将验证码保存在redis数据库中
            redisUtil.setStringObjectByMinutes(username, code, Integer.parseInt(time));
        } else {
            //验证码发送失败
            Result.error(resutl);
        }

        return null;
    }

    @Override
    public String getLoginCode(UsersDto usersDto) {
        int type = usersDto.getType();
        String code = null;
        String time = "5";
        String resutl = null;
        String username = usersDto.getUsername();
        QueryWrapper<Users> wrapper = new QueryWrapper<>();
        if (type == 2 || type == 1) {
            //手机号获取验证码
            wrapper.eq("phone", username);
            Users users = userMapper.selectOne(wrapper);
            if (!ObjectUtils.isEmpty(users)) { //手机号存在
                code = smsUtil.sendSms(username, time, SMSUtil.REGISTER);
            } else {
                resutl = "该手机号未注册！";
            }
        } else if (type == 6 || type == 5) {
            //获取邮箱验证码
            wrapper.eq("email", username);
            Users users = userMapper.selectOne(wrapper);
            if (!ObjectUtils.isEmpty(users)) {
                code = EmailUtil.sendCode(username);
            } else {
                resutl = "该邮箱未注册！";
            }
        }
        if (code != null && code.length() == 6) {
            // 验证码发送成功后将验证码保存在redis数据库中
            redisUtil.setStringObjectByMinutes(username, code, Integer.parseInt(time));
        } else {
            //验证码发送失败
            Result.error(code);
        }

        return resutl;
    }

    @Override
    public String updateByType(UsersDto usersDto) {
        int type = usersDto.getType();
        QueryWrapper<Users> usersQueryWrapper = new QueryWrapper<>();
        if (type == 1) {
            //手机号注册
            usersQueryWrapper.eq("phone", usersDto.getPhone());
        } else {
            //邮箱注册
            usersQueryWrapper.eq("email", usersDto.getEmail());
        }
        int update = userMapper.update(usersDto, usersQueryWrapper);
        if (update == 1) {
            return "success";
        }
        Result.error("信息更新失败！");
        return null;
    }

    @Override
    public String upload(MultipartFile file) {
        //文件名
        //获取文件名
        String originalFilename = file.getOriginalFilename();
        int i = originalFilename.lastIndexOf(".");
        String endName = originalFilename.substring(i);
        endName = endName.toLowerCase();
        //判断是否是指定类
        List<String> fileType = Arrays.asList(".gif", ".jpg", ".jfif", ".ico", ".png", ".bmp", ".svg");
        if (!fileType.contains(endName)) {
            Result.error("文件类型错误");
        }
        try {
            String path = qiniuUtil.setUploadManager(file.getInputStream());
            if (path == null) {
                Result.error("输入的字符不能为空！");
            }
            return path;
        } catch (Exception e) {
            e.printStackTrace();
            Result.error("文件上传失败");
        }
        return null;
    }

    @Override
    public void upUserHead(UsersDto usersDto) {
        int type = usersDto.getType();
        QueryWrapper<Users> usersQueryWrapper = new QueryWrapper<>();
        if (type == 1) {
            //手机号注册
            usersQueryWrapper.eq("phone", usersDto.getPhone());
        } else {
            //邮箱注册
            usersQueryWrapper.eq("email", usersDto.getEmail());
        }
        int update = userMapper.upHeadByType(usersDto);
        if (update != 1) {
            Result.error("信息更新失败！");
        }

    }

    @Override
    public Users getUsers(String token) {
        Users users = this.isUsers(token);
        users.setPassword(null);
        return users;
    }

    @Override
    public PageInfo<UsersVo> getList(UsersDto usersDto, Pageable page, HttpServletRequest request) {
        String tokenHeader = request.getHeader("token");
        // 解析token
        String jsonToken = EncryptUtil.decrypt(tokenHeader);
        AccessToken accessToken = JSONObject.parseObject(jsonToken, AccessToken.class);
        // 获取用户名，验证用户名
        Long userId = accessToken.getUserId();
        UsersVo loginUser = userMapper.getRoleById(userId);
        /*
         * 判断请求账号是否有权访问用户信息
         * 登录的账号不存在、账号的权限不够
         */
        UserRole userRole = userRoleMapper.isUserListByUserId(userId);
        if (loginUser == null || userRole == null) {
            Result.error("无权访问！");
        }

        PageHelper.startPage(page.getPageNumber(), page.getPageSize());
        List<UsersVo> list = userMapper.getListByUsers(usersDto);
        return new PageInfo<>(list);
    }

    public Users isUsers(String token) {
        if (token == null) {
            Result.error("token为空，当前未登录");
        }
        String jsonToken = EncryptUtil.decrypt(token);
        AccessToken accessToken = JSONObject.parseObject(jsonToken, AccessToken.class);
        // 验证token有效期
        if (System.currentTimeMillis() - accessToken.getExpire() > 0) {
            log.warn("token过期");
            Result.error("登录已过期，请重新登录");
        }

        // 获取用户名，验证用户名
        Long userId = accessToken.getUserId();
        Users users = userMapper.selectById(userId);
        if (ObjectUtils.isEmpty(users)) {
            log.warn("登录用户{}错误", userId);
            Result.error("未查询到用户信息！");
        }
        return users;
    }

    private Users emailCode(UsersDto usersDto) {

        String email = usersDto.getUsername();
        String code = (String) redisUtil.getStringObject(email);
        if (code == null) {
            Result.error("验证码已过期！");
        }
        if (!code.equals(usersDto.getCode())) {
            Result.error("验证码错误！");
        }
        QueryWrapper<Users> usersQueryWrapper = new QueryWrapper<>();
        usersQueryWrapper.eq("email", email);
        Users users = userMapper.selectOne(usersQueryWrapper);
        if (!ObjectUtils.isEmpty(users)) {
            return users;
        }
        return null;
    }

    private Users emailPass(UsersDto usersDto) {
        QueryWrapper<Users> usersQueryWrapper = new QueryWrapper<>();
        usersQueryWrapper.eq("email", usersDto.getUsername());
        usersQueryWrapper.eq("del_flag", 0);
        Users users = userMapper.selectOne(usersQueryWrapper);
        if (users != null) {
            String password = AesEncryptUtil.desEncrypt(usersDto.getPassword());
            if (StringUtils.equals(users.getPassword(), password)) {
                //密码相同
                return users;
            }
        }
        return null;
    }

    private Users qqPass(UsersDto usersDto) {
        QueryWrapper<Users> usersQueryWrapper = new QueryWrapper<>();
        usersQueryWrapper.eq("qq", usersDto.getUsername());
        usersQueryWrapper.eq("del_flag", 0);
        Users users = userMapper.selectOne(usersQueryWrapper);
        if (users != null) {
            String password = AesEncryptUtil.desEncrypt(usersDto.getPassword());
            if (StringUtils.equals(users.getPassword(), password)) {
                //密码相同
                return users;
            }
        }
        return null;
    }

    private Users vxPass(UsersDto usersDto) {
        QueryWrapper<Users> usersQueryWrapper = new QueryWrapper<>();
        usersQueryWrapper.eq("vx", usersDto.getUsername());
        usersQueryWrapper.eq("del_flag", 0);
        Users users = userMapper.selectOne(usersQueryWrapper);
        if (users != null) {
            String password = AesEncryptUtil.desEncrypt(usersDto.getPassword());
            if (StringUtils.equals(users.getPassword(), password)) {
                //密码相同
                return users;
            }
        }
        return null;
    }

    //手机验证码登录
    private Users phoneCode(UsersDto usersDto) {
        String phone = usersDto.getUsername();
        String code = (String) redisUtil.getStringObject(phone);
        if (code == null) {
            Result.error("验证码已过期！");
        }
        if (!code.equals(usersDto.getCode())) {
            Result.error("验证码错误！");
        }
        QueryWrapper<Users> usersQueryWrapper = new QueryWrapper<>();
        usersQueryWrapper.eq("phone", phone);
        usersQueryWrapper.eq("del_flag", 0);
        Users users = userMapper.selectOne(usersQueryWrapper);
        if (!ObjectUtils.isEmpty(users)) {
            return users;
        }
        return null;
    }

    private Users phonePass(UsersDto usersDto) {
        QueryWrapper<Users> usersQueryWrapper = new QueryWrapper<>();
        usersQueryWrapper.eq("phone", usersDto.getUsername());
        usersQueryWrapper.eq("del_flag", 0);
        Users users = userMapper.selectOne(usersQueryWrapper);
        if (users != null) {
            String password = AesEncryptUtil.desEncrypt(usersDto.getPassword());
            if (StringUtils.equals(users.getPassword(), password)) {
                //密码相同
                return users;
            }
        }
        Result.error("账号或密码错误！");
        return null;
    }

    /**
     * 发送祝福短信
     */
    @Override
    public void sendUserBirth() {
        SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd");
        String format = dateFormat.format(new Date());
        QueryWrapper<Users> wrapper = new QueryWrapper<>();
        wrapper.likeLeft("birth", format);
        List<Users> list = userMapper.selectList(wrapper);
        if (!ObjectUtils.isEmpty(list)) {
            list.forEach(users -> {
                String s = smsUtil.sendBirthSms(users.getPhone(), users.getName());
                if ("success".equals(s)) {
                    log.info("向用户{}发送生日祝福短信完成", users.getPhone());
                } else {
                    log.error("向用户{}发送生日祝福短信失败！", users.getPhone());
                }
            });
        }
    }
}
